package com.macro.mall.commission.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.macro.mall.commission.domain.UserBalanceChange;
import com.macro.mall.commission.entity.UserAccountEntity;
import com.macro.mall.commission.entity.UserBalanceChangeEntity;
import com.macro.mall.commission.mapper.UserAccountMapper;
import com.macro.mall.commission.mapper.UserBalanceChangeMapper;
import com.macro.mall.commission.service.UserAccountService;
import com.macro.mall.commission.service.UserBalanceChangeService;
import com.macro.mall.commission.service.bo.InsertUserAccountInput;
import com.macro.mall.commission.service.bo.InsertUserBalanceChangeInput;
import com.macro.mall.commission.service.bo.PagedQueryUserBalanceChangeInput;
import com.macro.mall.commission.service.bo.UpdateUserBalanceChangeInput;
import com.macro.mall.common.api.exception.BusinessException;
import com.macro.mall.common.api.util.BigDecimalUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;

/**
 * 用户账户余额变更记录Service
 *
 * @author xuyanjun
 * @date 2019-12-11
 */
@Slf4j
@Service
public class UserBalanceChangeServiceImpl implements UserBalanceChangeService {

    @Autowired
    private UserBalanceChangeMapper userBalanceChangeMapper;

    @Autowired
    private UserAccountService userAccountService;

    @Autowired
    private UserAccountMapper userAccountMapper;

    /**
     * 新增用户账户余额变更记录
     *
     * @param input input
     * @return 新增id
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public long insert(InsertUserBalanceChangeInput input) {
        int signedChangeAmount = input.getChangeAmount();

        UserAccountEntity userAccountEntity = obtainOrInitUserAccount(input.getUserId());

        switch (input.getChangeTypeEnum()) {
            case COMMISSION_INCOME:
                userAccountMapper.addBalance(userAccountEntity.getId(), input.getChangeAmount());
                break;
            case WITHDRAWAL:
                userAccountMapper.reduceBalance(userAccountEntity.getId(), input.getChangeAmount());
                signedChangeAmount = -signedChangeAmount;
                break;
            default:
                throw new IllegalArgumentException("无法处理的余额变动枚举:" + input.getChangeTypeEnum());
        }

        userAccountEntity = obtainOrInitUserAccount(input.getUserId());

        UserBalanceChangeEntity userBalanceChangeEntity = new UserBalanceChangeEntity();
        userBalanceChangeEntity
                .setUserId(input.getUserId())
                .setChangeAmount(signedChangeAmount)
                .setAfterChangeBalance(userAccountEntity.getBalance())
                .setChangeType(input.getChangeTypeEnum().getValue())
                .setReason(input.getChangeTypeEnum().getDescription())
                .setRemark(input.getRemark());

        LocalDateTime now = LocalDateTime.now();
        userBalanceChangeEntity.setCreateTime(now);
        userBalanceChangeEntity.setUpdateTime(now);

        userBalanceChangeMapper.insert(userBalanceChangeEntity);
        return userBalanceChangeEntity.getId();
    }

    /**
     * 获取或初始化用户账户
     *
     * @param userId userId
     * @return 用户账户
     */
    private UserAccountEntity obtainOrInitUserAccount(long userId) {
        UserAccountEntity userAccountEntity = userAccountService.getByUserId(userId);
        if (userAccountEntity == null) {
            InsertUserAccountInput insertUserAccountInput = new InsertUserAccountInput();
            insertUserAccountInput.setUserId(userId);

            userAccountService.insert(insertUserAccountInput);
            userAccountEntity = userAccountService.getByUserId(userId);
        }

        return userAccountEntity;
    }

    /**
     * 修改用户账户余额变更记录
     *
     * @param input input
     */
    @Override
    public void update(UpdateUserBalanceChangeInput input) {
        UserBalanceChangeEntity userBalanceChangeEntity = userBalanceChangeMapper.selectById(input.getId());
        if (userBalanceChangeEntity == null) {
            throw new BusinessException(String.format("未能根据Id:%s找到指定的用户账户余额变更记录。", input.getId()));
        }

        userBalanceChangeEntity = new UserBalanceChangeEntity();
        userBalanceChangeEntity
                .setId(input.getId())
                .setUserId(input.getUserId())
                .setChangeAmount(input.getChangeAmount())
                .setAfterChangeBalance(input.getAfterChangeBalance())
                .setChangeType(input.getChangeType())
                .setReason(input.getReason())
                .setRemark(input.getRemark());

        LocalDateTime now = LocalDateTime.now();
        userBalanceChangeEntity.setUpdateTime(now);

        userBalanceChangeMapper.updateById(userBalanceChangeEntity);
    }

    /**
     * 删除用户账户余额变更记录
     *
     * @param id id
     */
    @Override
    public void delete(long id) {
        userBalanceChangeMapper.deleteById(id);
    }

    /**
     * 根据Id获取用户账户余额变更记录
     *
     * @param id id
     * @return 用户账户余额变更记录
     */
    @Override
    public UserBalanceChangeEntity getById(long id) {
        return userBalanceChangeMapper.selectById(id);
    }

    /**
     * 根据批量Id获取用户账户余额变更记录
     *
     * @param batchIds 批量ids
     * @return 用户账户余额变更记录集合
     */
    @Override
    public List<UserBalanceChangeEntity> listByBatchIds(List<Long> batchIds) {
        if (batchIds == null || batchIds.isEmpty()) {
            return new ArrayList<>();
        }
        return userBalanceChangeMapper.selectBatchIds(batchIds);
    }

    /**
     * 分页查询
     *
     * @param input input
     * @return 分页的用户账户余额变更记录
     */
    @Override
    public Page<UserBalanceChangeEntity> pagedQuery(PagedQueryUserBalanceChangeInput input) {
        LambdaQueryWrapper<UserBalanceChangeEntity> queryWrapper = Wrappers.lambdaQuery();

        queryWrapper.eq(input.getMemberId() != null, UserBalanceChangeEntity::getUserId, input.getMemberId());

        PageHelper.startPage(input.getPageIndex(), input.getPageSize());

        return (Page<UserBalanceChangeEntity>) userBalanceChangeMapper.selectList(queryWrapper);
    }

    /**
     * 将实体对象转换成domain对象
     *
     * @param userBalanceChangeEntity 实体
     * @return userBalanceChange
     */
    @Override
    public UserBalanceChange entityToDomain(UserBalanceChangeEntity userBalanceChangeEntity) {
        if (userBalanceChangeEntity == null) {
            return null;
        }

        UserBalanceChange userBalanceChange = new UserBalanceChange();
        userBalanceChange
                .setId(userBalanceChangeEntity.getId())
                .setUserId(userBalanceChangeEntity.getUserId())
                .setCreateTime(userBalanceChangeEntity.getCreateTime())
                .setUpdateTime(userBalanceChangeEntity.getUpdateTime())
                .setChangeAmount(BigDecimalUtils.fromFengToYuan(userBalanceChangeEntity.getChangeAmount(),2))
                .setAfterChangeBalance(BigDecimalUtils.fromFengToYuan(userBalanceChangeEntity.getAfterChangeBalance(),2))
                .setChangeType(userBalanceChangeEntity.getChangeType())
                .setReason(userBalanceChangeEntity.getReason())
                .setRemark(userBalanceChangeEntity.getRemark());

        return userBalanceChange;
    }

    /**
     * 将实体对象转换成domain对象
     *
     * @param userBalanceChangeEntities 实体
     * @return userBalanceChanges
     */
    @Override
    public List<UserBalanceChange> entityToDomain(List<UserBalanceChangeEntity> userBalanceChangeEntities) {
        List<UserBalanceChange> result = new ArrayList<>();
        if (userBalanceChangeEntities == null) {
            return result;
        }

        for (UserBalanceChangeEntity userBalanceChangeEntity : userBalanceChangeEntities) {
            UserBalanceChange userBalanceChange = entityToDomain(userBalanceChangeEntity);
            result.add(userBalanceChange);
        }
        return result;
    }

}
